home *** CD-ROM | disk | FTP | other *** search
- /*
- * Router Discovery Protocol daemon suitable for using on Un*x systems.
- *
- * September 1989, Greg Satz
- *
- * Copyright (c) 1989 by cisco Systems, Inc.
- * All rights reserved.
- */
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <sys/file.h>
- #include <sys/mbuf.h>
- #ifdef sun
- #include <sys/limits.h>
- #else
- #define INT_MAX 0x7ffffff /* assume 32 bit ints */
- #endif
-
- #include <net/if.h>
- #include <net/route.h>
- #include <netinet/in.h>
- #ifndef pyr
- #include <netinet/if_ether.h>
- #else
- #include <net/if_ether.h>
- #endif
-
- #include <stdio.h>
- #include <signal.h>
- #include <errno.h>
- #include <netdb.h>
- #include <syslog.h>
- #include <nlist.h>
-
- /*
- * ICMP RDP packet format
- * use this rather than the definition in ip_icmp.h
- */
- struct irdppkt {
- unsigned char icmp_type; /* type of message */
- unsigned char icmp_code; /* type of sub code */
- unsigned short icmp_cksum; /* ones complement cksum of struct */
- unsigned char icmp_entries;/* number of entries in report */
- unsigned char icmp_size; /* size of each entry */
- unsigned short icmp_lifetime;/* lifetime of entries in this packet */
- struct addrgrp {
- struct in_addr ip;
- unsigned long priority;
- } addrs[1];
- };
- #ifndef ICMP_RDPADVERT
- #define ICMP_RDPADVERT 9 /* type for RDP advertisements */
- #define ICMP_RDPSOLICIT 10 /* type for RDP solicitations */
- #endif
-
- #define DEFAULT_IRDP_PRIORITY 100
- #define DEFAULT_IRDP_HOLDTIME 600
- #define DEFAULT_IRDP_MAXADVERTINT 600
- #define DEFAULT_IRDP_MINADVERTINT (DEFAULT_IRDP_MAXADVERTINT * 3 / 4)
-
- int hold_time = DEFAULT_IRDP_HOLDTIME; /* tell others how often to hold */
- int priority = DEFAULT_IRDP_PRIORITY; /* what priority do we advertise */
- int min_report_time = DEFAULT_IRDP_MINADVERTINT;/* how often to send reports */
- int max_report_time = DEFAULT_IRDP_MAXADVERTINT;
-
- #define ALARM_INTERVAL 1
-
- #define KERNEL "/vmunix"
- #define MEM "/dev/kmem"
-
- struct nlist nl[] = {
- #define X_ARPTAB 0
- { "_arptab" },
- #define X_ARPTAB_SIZE 1
- { "_arptab_size" },
- #define N_RTHOST 2
- { "_rthost" },
- #define N_RTNET 3
- { "_rtnet" },
- #define N_RTHASHSIZE 4
- { "_rthashsize" },
- { "" },
- };
-
- struct iface {
- char name[IFNAMSIZ];
- short flags;
- struct in_addr ipaddress;
- struct in_addr ipmask;
- struct in_addr ipbroadcast;
- struct iface *next;
- } *iflist;
-
- struct neighbor {
- struct in_addr ip;
- unsigned short priority;
- unsigned short holdtime;
- struct neighbor *next;
- };
-
- struct neighbor *rcvd_neighbors;
- struct neighbor *sent_neighbors;
-
- struct neighbor *default_neighbor;
-
-
- int debug; /* debugging flag */
- int flush; /* flush routing table flag */
- int logging; /* syslog logging flag */
- int metric; /* how do we run */
- int query_time; /* how often to send queries */
- int query;
- int report;
- int round_robin; /* how often to cycle parallel gws */
- int round;
-
- int s;
- struct sockaddr_in from;
- int fromlen;
- struct hostent *hp;
- unsigned char buf[BUFSIZ];
-
- int timer();
-
- /*
- * main
- * Perform IRDP processing depending on what we were told
- */
-
- main (argc, argv)
- int argc;
- char *argv;
- {
- int c, on = 1;
- struct irdppkt *irdp;
- struct addrgrp ag;
- struct in_addr bip;
- struct protoent *proto;
- int oldmask;
- extern char *optarg;
- extern int optind;
- extern int errno;
-
- debug = 0;
- flush = 0;
- logging = 0;
- metric = 1; /* default to one hop */
- priority = DEFAULT_IRDP_PRIORITY;
- hold_time = DEFAULT_IRDP_HOLDTIME;
- query_time = 0;
- min_report_time = 0;
- max_report_time = 0;
- round_robin = 0;
- iflist = NULL;
- rcvd_neighbors = NULL;
- sent_neighbors = NULL;
- default_neighbor = NULL;
- bip.s_addr = 0L;
- #ifdef LOG_DAEMON
- openlog("irdpd", LOG_PID, LOG_DAEMON);
- #else
- openlog("irdpd", LOG_PID);
- #endif
- while ((c = getopt(argc, argv, "dfh:lm:p:q:r:t:")) != EOF)
- switch (c) {
- case 'd': /* debug */
- debug = 1;
- break;
- case 'f': /* flush */
- flush = 1;
- break;
- case 'h': /* hold time */
- hold_time = atoi(optarg);
- if (hold_time < 0) {
- fprintf(stderr, "%s: illegal hold time value - %d",
- argv[0], hold_time);
- exit(1);
- }
- break;
- case 'l': /* logging */
- logging = 1;
- break;
- case 'm': /* metric */
- metric = atoi(optarg);
- if (metric < 0) {
- fprintf(stderr, "%s: illegal metric value - %d",
- argv[0], metric);
- exit(1);
- }
- break;
- case 'p': /* priority */
- priority = atoi(optarg);
- if (priority < 0) {
- fprintf(stderr, "%s: illegal priority value - %d",
- argv[0], priority);
- exit(1);
- }
- break;
- case 'q': /* query */
- query_time = atoi(optarg);
- if (query_time < 0) {
- fprintf(stderr, "%s: illegal querying value - %d",
- argv[0], query_time);
- exit(1);
- }
- break;
- case 'r': /* min report */
- min_report_time = atoi(optarg);
- if (min_report_time < 0) {
- fprintf(stderr, "%s: illegal reporting value - %d",
- argv[0], min_report_time);
- exit(1);
- }
- break;
- case 'R': /* max report */
- max_report_time = atoi(optarg);
- if (max_report_time < 0) {
- fprintf(stderr, "%s: illegal reporting value - %d",
- argv[0], max_report_time);
- exit(1);
- }
- break;
- case 't': /* time */
- round_robin = atoi(optarg);
- if (round_robin < 0) {
- fprintf(stderr, "%s: illegal round robin value - %d",
- argv[0], round_robin);
- exit(1);
- }
- round_robin *= 60; /* make seconds */
- break;
- default:
- fprintf(stderr, "%s: illegal switch -%s", argv[0], optarg);
- exit(1);
- }
-
- if (query_time != 0 && max_report_time != 0) {
- fprintf(stderr, "%s: cannot report and query simultaneously.\n",
- argv[0]);
- exit(1);
- }
-
- bzero(&ag, sizeof(struct addrgrp));
- while (argc != optind) {
- ag.ip.s_addr = inet_addr(argv[optind]);
- if (ag.ip.s_addr == -1) {
- hp = gethostbyname(argv[optind]);
- if (hp == NULL) {
- fprintf(stderr, "%s: %s: unknown host\n", argv[0],
- argv[optind]);
- exit(1);
- }
- bcopy(hp->h_addr, &ag.ip, sizeof(ag.ip));
- }
- enter_neighbor(&sent_neighbors, ag.ip, 0, 0);
- optind++;
- }
-
- /* seed random number generator */
- srandom((int) (time(0L) & INT_MAX));
-
- if (query_time)
- query = random() % query_time;
-
- if (max_report_time)
- report = min_report_time +
- (random() % (max_report_time - min_report_time));
-
- round = round_robin;
-
- if (metric == 0 || flush) {
- nlist(KERNEL, nl);
- if (nl[X_ARPTAB].n_value == 0) {
- fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
- exit(1);
- }
- if (nl[X_ARPTAB_SIZE].n_value == 0) {
- fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
- exit(1);
- }
- if (nl[N_RTHOST].n_value == 0) {
- fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
- exit(1);
- }
- if (nl[N_RTNET].n_value == 0) {
- fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
- exit(1);
- }
- if (nl[N_RTHASHSIZE].n_value == 0) {
- fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
- exit(1);
- }
- }
- if (debug)
- syslog(LOG_DEBUG, "server starting");
-
- if (!debug) {
- if (fork())
- exit(0);
- for (c = 0; c < getdtablesize(); c++)
- (void) close(c);
- (void) open("/", O_RDONLY);
- (void) dup2(0, 1);
- (void) dup2(0, 2);
- c = open("/dev/tty", O_RDWR);
- if (c >= 0) {
- ioctl(c, TIOCNOTTY, (char *)0);
- (void) close(c);
- }
- #ifdef LOG_DAEMON
- openlog("irdpd", LOG_PID, LOG_DAEMON);
- #else
- openlog("irdpd", LOG_PID);
- #endif
- }
-
- /*
- * Get listener socket
- */
- if ((proto = getprotobyname("icmp")) == NULL) {
- syslog(LOG_ERR, "getprotobyname: %m");
- exit(1);
- }
- if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
- syslog(LOG_ERR, "socket: irdp %m");
- exit(1);
- }
-
- #ifdef SO_BROADCAST
- if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
- syslog(LOG_ERR, "setsockopt: %m");
- exit(1);
- }
- #endif
-
- build_iflist();
- irdp_solicit(bip);
- signal(SIGALRM, timer);
- timer();
-
- /*
- * Now do the work
- */
-
- for (;;) {
- fromlen = sizeof(from);
- c = recvfrom(s, buf, sizeof(buf), 0, (caddr_t)&from, &fromlen);
- if (c <= 0) {
- if (errno == EINTR)
- continue;
- syslog(LOG_ERR, "recvfrom: %m");
- exit(1);
- }
- irdp = (struct irdppkt *)buf;
-
- if (irdp->icmp_type != ICMP_RDPADVERT &&
- irdp->icmp_type != ICMP_RDPSOLICIT)
-
- if (debug) {
- hp = gethostbyaddr(&from.sin_addr, sizeof(struct in_addr),
- AF_INET);
- syslog(LOG_DEBUG, "%s received from %s",
- irdp->icmp_type == ICMP_RDPADVERT ? "ADVERT" : "SOLICIT",
- hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));
- }
-
- oldmask = sigblock(sigmask(SIGALRM));
- if (irdp->icmp_type == ICMP_RDPADVERT) {
- if (max_report_time == 0) /* if we're end node */
- irdp_procadvert(&from, buf);
- } else {
- if (max_report_time != 0) /* if we're router */
- irdp_procsolicit(&from, buf);
- }
- sigsetmask(oldmask);
- }
- }
-
- /*
- * find_neighbor
- * Look for a given neighbor in the list and return ptr or NULL
- */
-
- struct neighbor *find_neighbor (nt, ip)
- struct neighbor **nt;
- struct in_addr ip;
- {
- struct neighbor *p;
-
- for (p = *nt; p != NULL; p = p->next)
- if (p->ip.s_addr == ip.s_addr)
- break;
- return(p);
- }
-
- /*
- * enter_neighbor
- * Enter a new neighbor into the table in priority order
- */
-
- enter_neighbor (nt, ip, priority, holdtime)
- struct neighbor **nt;
- struct in_addr ip;
- int priority, holdtime;
- {
- struct neighbor *p, *pp, *newp;
-
- newp = (struct neighbor *)malloc(sizeof(struct neighbor));
- if (newp == NULL)
- return;
-
- newp->ip = ip;
- newp->priority = priority;
- newp->holdtime = holdtime;
- newp->next = NULL;
- for (p = pp = *nt; p != NULL; pp = p, p = p->next)
- if (newp->priority > p->priority)
- break;
- if (p == NULL) {
- if (*nt == NULL)
- *nt = newp;
- else
- pp->next = newp;
- } else if (p == pp) {
- newp->next = *nt;
- *nt = newp;
- } else {
- pp->next = newp;
- newp->next = p;
- }
- }
-
- /*
- * delete_neighbor
- * Remove neighbor from the list
- */
-
- delete_neighbor (nt, dp)
- struct neighbor **nt;
- struct neighbor *dp;
- {
- struct neighbor *p, *pp;
-
- for (p = pp = *nt; p != NULL; pp = p, p = p->next)
- if (p == dp)
- break;
- if (p == pp)
- *nt = p->next;
- else
- pp->next = p->next;
- free(p);
-
- }
-
- /*
- * robin_neighbor
- * Perform round robin on received neighbors of equal priority
- */
-
- robin_neighbor ()
- {
- struct neighbor *p, *pp;
-
- /*
- * Find where next lower priorty starts
- */
- for (p = pp = rcvd_neighbors; p != NULL; p = p->next)
- if (default_neighbor->priority > p->priority)
- break;
- /*
- * If there is only a single entry, then don't bother
- */
- if (default_neighbor == pp)
- return;
-
- /*
- * Splice old one at end of equal priority list
- */
- rcvd_neighbors = default_neighbor->next;
- pp->next = default_neighbor;
- default_neighbor->next = p;
- update_routes();
- }
-
- /*
- * irdp_procadvert
- * handle processing of IRDP advertisements
- */
-
- irdp_procadvert (from, irdp)
- struct sockaddr_in *from;
- struct irdppkt *irdp;
- {
- struct neighbor *p;
- struct addrgrp *a;
-
- a = irdp->addrs;
- while (irdp->icmp_entries-- > 0) {
- if (valid_address(a->ip)) {
- p = find_neighbor(&sent_neighbors, a->ip);
- if (p != NULL)
- p->holdtime = ntohs(irdp->icmp_lifetime);
- p = find_neighbor(&rcvd_neighbors, a->ip);
- if (p == NULL || p->priority != ntohs(a->priority)) {
- if (p != NULL) {
- if (flush)
- flush_routes(p->ip);
- delete_neighbor(&rcvd_neighbors, p);
- }
- enter_neighbor(&rcvd_neighbors, a->ip,
- ntohs(a->priority), ntohs(irdp->icmp_lifetime));
- update_routes();
- round = round_robin; /* restart timer */
- } else
- p->holdtime = ntohs(irdp->icmp_lifetime);
- } else if (debug)
- syslog(LOG_DEBUG, "invalid IP address: %s",
- inet_ntoa(a->ip));
- a++;
- }
- }
-
- /*
- * irdp_procsolicit
- * Process a solicitation send out irdp packets on all ports
- */
-
- irdp_procsolicit (from, irdp)
- struct sockaddr_in *from;
- struct irdppkt *irdp;
- {
- }
-
- /*
- * timer
- * Wake up once in a while and process running timers, etc.
- */
-
- timer ()
- {
- struct neighbor *p, *dp;
- struct in_addr bip;
-
- bip.s_addr = 0L;
- if (max_report_time != 0) {
- if (report <= 0) {
- irdp_advert(bip);
- report = min_report_time +
- (random() % (max_report_time - min_report_time));
- } else
- report -= ALARM_INTERVAL;
- } else {
- if (query_time != 0) {
- query -= ALARM_INTERVAL;
- if (query <= 0) {
- for (p = sent_neighbors; p != NULL; p = p->next)
- irdp_solicit(p->ip);
- query = query_time;
- }
- }
- for (p = rcvd_neighbors; p != NULL; ) {
- dp = p;
- p = p->next;
- dp->holdtime -= ALARM_INTERVAL;
- if (dp->holdtime <= 0) {
- if (flush)
- flush_routes(dp->ip);
- delete_neighbor(&rcvd_neighbors, dp);
- update_routes();
- round = round_robin; /* restart timer */
- }
- }
- }
- if (round_robin != 0) {
- round -= ALARM_INTERVAL;
- if (round <= 0) {
- if (default_neighbor != NULL)
- robin_neighbor();
- round = round_robin;
- }
- }
- alarm(ALARM_INTERVAL);
- }
-
- /*
- * irdp_solicit
- * Send a IRDP solictation - if IP = 0, send to all broadcast interfaces
- */
-
- irdp_solicit (ip)
- struct in_addr ip;
- {
- struct irdppkt irdp;
- struct sockaddr_in sin;
- struct iface *ifp;
- struct neighbor *p;
-
- bzero(&irdp, sizeof(irdp));
- irdp.icmp_type = ICMP_RDPSOLICIT;
- irdp.icmp_cksum = in_cksum(irdp, sizeof(irdp)-sizeof(struct addrgrp));
-
- bzero(&sin, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr = ip;
- if (ip.s_addr == 0L) {
- for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
- if ((ifp->flags & IFF_BROADCAST) == 0)
- continue;
- sin.sin_addr = ifp->ipbroadcast;
- (void) sendto(s, &irdp, sizeof(irdp) - sizeof(struct addrgrp), 0,
- &sin, sizeof(sin));
- }
- for (p = sent_neighbors; p != NULL; p = p->next)
- irdp_solicit(p->ip);
- } else
- (void) sendto(s, &irdp, sizeof(irdp) - sizeof(struct addrgrp), 0,
- &sin, sizeof(sin));
- }
-
- /*
- * irdp_advert
- * Send a IRDP REPORT message
- */
-
- irdp_advert (ip)
- struct in_addr ip;
- {
- }
-
- /*
- * build_iflist
- * Build a list of interfaces and accompaning information
- */
-
- build_iflist ()
- {
- int n;
- char ifbuf[BUFSIZ];
- struct ifconf ifc;
- struct ifreq *ifr, ifreq;
- struct iface *ifp;
- struct sockaddr_in *sa;
- short flags;
-
- ifc.ifc_len = sizeof(ifbuf);
- ifc.ifc_buf = ifbuf;
- if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
- syslog(LOG_ERR, "ioctl(IFCONF): %m");
- exit(1);
- }
- ifr = ifc.ifc_req;
- for (n = ifc.ifc_len / sizeof(struct ifreq); n > 0; n--, ifr++) {
- /*
- * Ignore the loopback interface
- */
- if (strncmp(ifr->ifr_name, "lo", 2) == 0)
- continue;
- /*
- * Ignore all interfaces which aren't running
- */
- strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
- if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
- continue;
- else
- flags = ifreq.ifr_flags;
- if ((flags & IFF_RUNNING) == 0)
- continue;
- sa = (struct sockaddr_in *)&ifr->ifr_addr;
- /*
- * Ignore non-internet family and 0.0.0.0
- */
- if (sa->sin_family != AF_INET || sa->sin_addr.s_addr == 0L)
- continue;
- ifp = (struct iface *)malloc(sizeof(struct iface));
- if (ifp == NULL)
- break;
- bzero(ifp, sizeof(struct iface));
- strncpy(ifp->name, ifr->ifr_name, sizeof(ifp->name));
- ifp->ipaddress = sa->sin_addr;
- ifp->flags = flags;
- strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
- if (ioctl(s, SIOCGIFNETMASK, &ifreq) >= 0) {
- sa = (struct sockaddr_in *)&ifreq.ifr_addr;
- ifp->ipmask = sa->sin_addr;
- }
- if (ifp->flags & IFF_BROADCAST) {
- strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
- if (ioctl(s, SIOCGIFBRDADDR, &ifreq) >= 0) {
- sa = (struct sockaddr_in *)&ifreq.ifr_addr;
- ifp->ipbroadcast = sa->sin_addr;
- }
- }
- if (iflist == NULL)
- iflist = ifp;
- else {
- ifp->next = iflist;
- iflist = ifp;
- }
- }
- }
-
- /*
- * valid_address
- * Determine if give IP address is something we grok.
- */
-
- valid_address (ip)
- struct in_addr ip;
- {
- struct iface *ifp;
-
- for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
- if ((ip.s_addr & ifp->ipmask.s_addr) ==
- (ifp->ipaddress.s_addr & ifp->ipmask.s_addr))
- return(1);
- }
- return(0);
- }
-
- /*
- * update_routes
- * Update default route if necessary when something changes
- */
-
- update_routes ()
- {
- struct rtentry rt;
- struct sockaddr_in *sa;
- struct in_addr inet_makeaddr();
-
- if (default_neighbor == rcvd_neighbors)
- return;
-
- bzero(&rt, sizeof(rt));
- rt.rt_flags = RTF_UP;
- if (metric > 0)
- rt.rt_flags |= RTF_GATEWAY;
- sa = (struct sockaddr_in *)&rt.rt_dst;
- sa->sin_family = AF_INET;
- sa->sin_addr = inet_makeaddr(0, INADDR_ANY);
- sa = (struct sockaddr_in *)&rt.rt_gateway;
- sa->sin_family = AF_INET;
- if (default_neighbor != NULL) {
- sa->sin_addr = default_neighbor->ip;
- if (metric == 0)
- flush_arp();
- if (logging)
- syslog(LOG_NOTICE, "deleting old default: %s",
- inet_ntoa(sa->sin_addr));
- if (!debug)
- (void) ioctl(s, SIOCDELRT, &rt);
- }
- default_neighbor = rcvd_neighbors;
- if (default_neighbor == NULL)
- return;
- sa->sin_addr = default_neighbor->ip;
- if (logging)
- syslog(LOG_NOTICE, "adding new default: %s",
- inet_ntoa(sa->sin_addr));
- if (!debug)
- (void) ioctl(s, SIOCADDRT, &rt);
- }
-
- /*
- * flush_arp
- * Flush the ARP tables. Used when we delete a default route and metric
- * is zero.
- */
-
- flush_arp ()
- {
- int size, fd;
- int arptab_size;
- struct arptab *atp;
- struct arptab *at;
- struct arpreq ar;
- struct sockaddr_in *sa;
-
- if (logging)
- syslog(LOG_NOTICE, "flushing ARP tables");
- if (debug)
- return;
- fd = open(MEM, O_RDONLY);
- if (fd < 0) {
- syslog(LOG_ERR,"%s: cannot open", MEM);
- exit(1);
- }
-
- if (lseek(fd, (long)nl[X_ARPTAB_SIZE].n_value, 0) == -1 ||
- read(fd, &arptab_size, sizeof(arptab_size)) != sizeof(arptab_size) ||
- arptab_size < 0 || arptab_size > 10000) {
- syslog(LOG_ERR, "bad ARP namelist");
- exit(1);
- }
- size = arptab_size * sizeof(struct arptab);
- atp = (struct arptab *)malloc(size);
- at = atp;
- if (at == NULL) {
- close(fd);
- return;
- }
-
- if (lseek(fd, (long)nl[X_ARPTAB].n_value, 0) == -1 ||
- read(fd, (char *)at, size) != size) {
- syslog(LOG_ERR, "error reading ARP table %m");
- exit(1);
- }
- bzero(&ar, sizeof(ar));
- sa = (struct sockaddr_in *)&ar.arp_pa;
- sa->sin_family = AF_INET;
- for ( ; arptab_size-- > 0; at++) {
- #ifndef pyr
- if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
- #else
- struct sockaddr_in sin;
-
- bcopy(&at->at_addr, &sin, sizeof(struct sockaddr_in));
- if (sin.sin_addr.s_addr == 0 || at->at_flags == 0)
- #endif
- continue;
- if (at->at_flags & ATF_PERM)
- continue;
- #ifndef pyr
- sa->sin_addr = at->at_iaddr;
- #else
- sa->sin_addr = sin.sin_addr;
- #endif
- (void) ioctl(s, SIOCDARP, &ar);
- }
- close(fd);
- free(atp);
- }
-
- /*
- * flush_routes
- * Flush the routing table. We do this when asked.
- */
-
- flush_routes (ip)
- struct in_addr ip;
- {
- struct in_addr gwin, dstin;
- struct mbuf mb;
- register struct rtentry *rt;
- register struct mbuf *mbp;
- struct mbuf **routehash;
- int rthashsize, i, doinghost = 1, fd;
-
- fd = open(MEM, O_RDONLY);
- if (fd < 0) {
- syslog(LOG_ERR,"%s: cannot open", MEM);
- exit(1);
- }
-
- if (lseek(fd, nl[N_RTHASHSIZE].n_value, 0) == -1 ||
- read(fd, &rthashsize, sizeof (rthashsize)) != sizeof(rthashsize)) {
- syslog(LOG_ERR, "bad ROUTE namelist");
- exit(1);
- }
- if (logging)
- syslog(LOG_NOTICE, "flushing routes via %s", inet_ntoa(ip));
- routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
- if (routehash == NULL) {
- close(fd);
- return;
- }
- if (lseek(fd, nl[N_RTHOST].n_value, 0) == -1 ||
- read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
- rthashsize*sizeof(struct mbuf *)) {
- syslog(LOG_ERR, "error reading ROUTE table %m");
- exit(1);
- }
- again:
- for (i = 0; i < rthashsize; i++) {
- if (routehash[i] == 0)
- continue;
- mbp = routehash[i];
- while (mbp) {
- if (lseek(fd, mbp, 0) == -1 ||
- read(fd, &mb, sizeof (mb)) != sizeof(mb))
- goto done;
- rt = mtod(&mb, struct rtentry *);
- if ((rt->rt_flags & RTF_GATEWAY) &&
- rt->rt_gateway.sa_family == AF_INET) {
- gwin = ((struct sockaddr_in *)&rt->rt_gateway)->sin_addr;
- dstin = ((struct sockaddr_in *)&rt->rt_dst)->sin_addr;
- /*
- * Flush all routes through this device except
- * default which is done later.
- */
- if (gwin.s_addr == ip.s_addr && dstin.s_addr != 0L) {
- if (logging) {
- syslog(LOG_NOTICE, "flushing route %s",
- inet_ntoa(dstin));
- }
- if (!debug)
- (void) ioctl(s, SIOCDELRT, (caddr_t)rt);
- }
- }
- mbp = mb.m_next;
- }
- }
- if (doinghost) {
- if (lseek(fd, nl[N_RTNET].n_value, 0) == -1 ||
- read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
- rthashsize*sizeof(struct mbuf *))
- goto done;
- doinghost = 0;
- goto again;
- }
- done:
- free(routehash);
- close(fd);
- }
-
- /*
- * Copyright (c) 1987 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
- /*
- * I N _ C K S U M
- *
- * Checksum routine for Internet Protocol family headers (C Version)
- *
- */
- int
- in_cksum(addr, len)
- unsigned short *addr;
- int len;
- {
- register int nleft = len;
- register u_short *w = addr;
- register u_short answer;
- register int sum = 0;
- u_short odd_byte = 0;
-
- /*
- * Our algorithm is simple, using a 32 bit accumulator (sum),
- * we add sequential 16 bit words to it, and at the end, fold
- * back all the carry bits from the top 16 bits into the lower
- * 16 bits.
- */
- while( nleft > 1 ) {
- sum += *w++;
- nleft -= 2;
- }
-
- /* mop up an odd byte, if necessary */
- if( nleft == 1 ) {
- *(u_char *)(&odd_byte) = *(u_char *)w;
- sum += odd_byte;
- }
-
- /*
- * add back carry outs from top 16 bits to low 16 bits
- */
- sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
- sum += (sum >> 16); /* add carry */
- answer = ~sum; /* truncate to 16 bits */
- return (answer);
- }
-